﻿using System;
using System.Collections.Generic;
using NCommet.Core.Agents;
using System.ComponentModel;

namespace NCommet.Core.Services
{
    /// <summary>
    /// NCommetContainer is a singleton object container that holds the concrete implementations of all
    /// the agents available in NCommet.
    /// </summary>
    public sealed class NCommetContainer
    {
        #region Singleton Implementation
        class Nested
        {
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static Nested() { }
            internal static readonly NCommetContainer instance = new NCommetContainer();
        }

        public static NCommetContainer Instance { get { return Nested.instance; } }

        private NCommetContainer()
        {
        }
        #endregion

        #region Modules Support
        private List<IModule> modules = new List<IModule>();

        /// <summary>
        /// Adds a new <see cref="NCommet.Core.Agents.IModule"/>
        /// </summary>
        /// <param name="module">The <see cref="NCommet.Core.Agents.IModule"/> to be added.</param>
        /// <exception cref="ArgumentException">
        /// If the module is already loaded.
        /// </exception>        
        public void AddModule(IModule module)
        {
            if (modules.Contains(module))
                throw new ArgumentException("Module already loaded", "module");
            modules.Add(module);
            module.InitModule();
        }
        #endregion

        #region Contained Agents

        private IPersister persister;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.IPersister"/>
        /// </summary>
        public IPersister Persister
        {
            get { return persister; }
            set { persister = value; }
        }

        private ISorter sorter;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.ISorter"/>
        /// </summary>
        public ISorter Sorter
        {
            get { return sorter; }
            set { sorter = value; }
        }

        private ISearcher searcher;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.ISearcher"/>
        /// </summary>
        public ISearcher Searcher
        {
            get { return searcher; }
            set { searcher = value; }
        }

        private ITypedTreeValidator typedTreeValidator;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.ITypedTreeValidator"/>
        /// </summary>
        public ITypedTreeValidator TypedTreeValidator
        {
            get { return typedTreeValidator; }
            set { typedTreeValidator = value; }
        }

        private IDaoEventsSink daoEventsSink;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.IDaoEventsSink"/>
        /// </summary>
        public IDaoEventsSink DaoEventsSink
        {
            get { return daoEventsSink; }
            set
            {
                if (daoEventsSink != value)
                {
                    daoEventsSink = value;
                    // Remind EventSink to subscribe to PropertyChanged event.
                    EventSink sink = NCommet.Core.Services.EventSink.Instance;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("DaoEventsSink"));
                }
            }
        }

        private IAuthorizationManager authorizationManager;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.IAuthorizationManager"/>
        /// </summary>
        public IAuthorizationManager AuthorizationManager
        {
            get { return authorizationManager; }
            set { authorizationManager = value; }
        }

        private IWhoAmI whoAmI;

        /// <summary>
        /// The implementation of <see cref="NCommet.Core.Agents.IWhoAmI"/>
        /// </summary>
        public IWhoAmI WhoAmI
        {
            get { return whoAmI; }
            set { whoAmI = value; }
        }

        #endregion

        /// <summary>
        /// Occurs when the implementation of an interface is changed.        
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    }
}
